#ifndef COMPANY_H
#define COMPANY_H

#include "employee.h"
#include "AVLTree.h"
#include "shared_ptr.h"
#include "common.h"

/**
 * This exception is used to handle incoming input violation
 */
class InvalidSalary : public InvalidInputExcpetion {};

/**
 * These exceptions are used to handle internal exceptions
 */
class EmployeeNotInCompany : public FailureException {};
class NoEmployees : public FailureException {};

/**
 * This class defines a company by holding its tree of employees and salararies
 * it also has Median salaray, highest salary and the salary coefficient
 */
class Company
{
public:
	/**
	 * Constructor: creates a company with a certain number
	 * \param The company number
	 */
	Company(int id);

public:
	/**
	 * This function hires a given employee (if possible) to the company
	 * \param A shared_pointer to the employee
	 */
	void HireEmployee(shared_ptr<Employee> empPtr);

	/**
	 * This function fires an employee from the company (if possible)
	 * \param The ID number of the employee
	 * \param The salary of the employee
	 */
	void FireEmployee(int employeeId, const rational::Rational& salary);

	/**
	 * This function retrieves the median salary of the company
	 */
	rational::Rational GetMedianSalary() const;

	/**
	 * This function retrieves the maximal salary of the company
	 */
	rational::Rational GetMaxSalary() const;

	/**
	 * This function updates the salary coefficient of the company
	 * \param The new salary coefficient
	 */
	void UpdateSalary(const rational::Rational& coefficient);

	/**
	 * This function merges two companies together, retaining the salaries of
	 * the merged company
	 * \param A reference to the company being merged in
	 */
	void Merge(Company& other);

	/**
	 * This function gets the real salary of a certain employee
	 * \param A reference to the employee
	 */
	rational::Rational GetRealSalary(const Employee& employee) const;

private:
	typedef myVector<
				myPair<
					myPair<rational::Rational, int> , shared_ptr<Employee> > >
			SalaryEmployeeVector;
	void UpdateMedAndMax();
	static void MergeVectors(const SalaryEmployeeVector& vec1,
					  const SalaryEmployeeVector& vec2,
					  SalaryEmployeeVector& res);
	static void NormalizeSalaries(Company& comp, SalaryEmployeeVector& vec);
private:
	rational::Rational _MedianSalary, _MaxSalary, _SalaryCoefficient;
	AVLTree<myPair<rational::Rational, int> , shared_ptr<Employee> > _Employees;
	int _Id;
};

#endif // COMPANY_H
